#include <sys/stat.h>
#include <sys/types.h>
#include "bss.h"
#include "../seq/tree.h"


#define ALL_ACCESS (S_IRUSR | S_IWUSR | S_IXUSR | \
                    S_IRGRP | S_IWGRP | S_IXGRP | \
                    S_IROTH | S_IWOTH | S_IXOTH)

#define FSCANLINE(x) my_scanline(readfile,x,__LINE__)
#define ERRLINE(x,y) {fprintf(stderr,"%d:BAD LINE:%s\n",__LINE__,x);return y;}

char bss_fields[BSS_FIELD_MAXNUM][BSS_FIELD_MAXSIZE+1];

BSS_TYPE bss_column_order[BSS_NUMTYPES];
int bss_ncols;

int my_scanline(FILE* f,char* line,int linenum)
{
    line[0] = 0;
    char* ret = fgets(line,1023,f);
    if (ret != NULL)
    {
        if (line[strlen(line)-1] == '\n')
        {
            line[strlen(line)-1] = 0;   
        }
    }
    //printf("%d:%s\n",linenum,line);fflush(0);
    return (ret == NULL ? 0 : 1);
}

/* set the column order for the initial bss file write,
    after which column order comes from the columns in the file */
void set_column_order(struct bss_instance* bsi)
{
    if (bsi->program != BLAT)
    {

        bss_ncols = 16;
        bss_column_order[0] = BSS_BES;    
        bss_column_order[1] = BSS_RC;    
        bss_column_order[2] = BSS_SEQCTG;    
        bss_column_order[3] = BSS_CLONE;    
        bss_column_order[4] = BSS_CTGLR;    
        bss_column_order[5] = BSS_MARKER;    
        bss_column_order[6] = BSS_SCORE;    
        bss_column_order[7] = BSS_EVALUE;    
        bss_column_order[8] = BSS_IDENTITY; 
        bss_column_order[9] = BSS_MATCH; 
        bss_column_order[10] = BSS_QLEN;    
        bss_column_order[11] = BSS_QSTART;    
        bss_column_order[12] = BSS_QEND;    
        bss_column_order[13] = BSS_TLEN;    
        bss_column_order[14] = BSS_TSTART;    
        bss_column_order[15] = BSS_TEND;    
        //bss_column_order[16] = BSS_QUERY;    
        //bss_column_order[17] = BSS_TARGET;    

    }
    else  // BLAT
    {

        bss_ncols = 16;
        bss_column_order[0] = BSS_BES;    
        bss_column_order[1] = BSS_SEQCTG;    
        bss_column_order[2] = BSS_RC;    
        bss_column_order[3] = BSS_CLONE;    
        bss_column_order[4] = BSS_CTGLR;    
        bss_column_order[5] = BSS_MARKER;    
        bss_column_order[6] = BSS_SCORE;    
        bss_column_order[7] = BSS_MATCH;    
        bss_column_order[8] = BSS_IDENTITY; 
        bss_column_order[9] = BSS_INTRON; 
        bss_column_order[10] = BSS_QLEN;    
        bss_column_order[11] = BSS_QSTART;    
        bss_column_order[12] = BSS_QEND;    
        bss_column_order[13] = BSS_TLEN;    
        bss_column_order[14] = BSS_TSTART;    
        bss_column_order[15] = BSS_TEND;    
        //bss_column_order[16] = BSS_QUERY;    
        //bss_column_order[17] = BSS_TARGET;    

    }
}
void bss_format_field(char* field,BSS_HIT* hit, BSS_TYPE type)
{
    char fmt[100];
    char tmp[20];
    switch (type)
    {
        case BSS_QSTART:
        case BSS_QEND:
        case BSS_TSTART:
        case BSS_TEND:
        case BSS_TLEN:
        case BSS_SEQCTG:
        case BSS_SCORE:
        case BSS_CTG:
        case BSS_HITLEN:
        case BSS_INTRON: 
        case BSS_QLEN: 
            sprintf(fmt,"%%-%dd ",bss_col_widths[type]);
            sprintf(field,fmt,hit->data[type].i);
            break;

        case BSS_BES:
        case BSS_MARKER:
        case BSS_SEQ:
        case BSS_RC:
        case BSS_CLONE:
        case BSS_EVALUE:
        case BSS_QUERY:
        case BSS_TARGET:
        case BSS_CTGLR:
        case BSS_LR:
            sprintf(fmt,"%%-%ds ",bss_col_widths[type]);
            sprintf(field,fmt,hit->data[type].str);
            break;
        case BSS_MATCH: 
        case BSS_IDENTITY:
            sprintf(fmt,"%%-%ds ",bss_col_widths[type]);
            sprintf(tmp,"%d%%",hit->data[type].i);
            sprintf(field,fmt,tmp);
            break;
        default:
            assert(0);
        break;
    }
}
void output_column_headers(FILE* f)
{
    char line[1000];
    char fmt[100];
    char field[100];
    int j;

    line[0] = 0;
    for (j = 0; j < bss_ncols; j++)
    {
        sprintf(fmt,"%%-%ds ",bss_col_widths[bss_column_order[j]]);
        sprintf(field,fmt,bss_headers[bss_column_order[j]]);  
        strcat(line,field);
    }
    strcat(line,"\n");
    fputs(line,f);
}
void make_unique_name(char* file, char* buf)
{
    struct stat s;
    int i;

    for (i = 0; i < 1000000; i++)
    {
        sprintf(buf,"%s.save.%d",file,i);
        if (stat(buf,&s) != 0)
        {
            return;
        }
    }
    assert(0); // hard to imagine 1M tries would fail
}
void really_write_bss_file(struct bss_instance* pbsi, int*);
void write_bss_file(struct bss_instance* pbsi, int clobber)
{
    struct stat s;
    gchar* m;
    int messresult;
    char newname[MAXPATHLEN];
    int ihit;    

    clobber = 1; // they see a warning anyway

    printf("write %s\n",pbsi->bssfile);fflush(0);
    if (stat(pbsi->bssfile, &s) == 0)
    {
        if (clobber == 0)
        {
            make_unique_name(pbsi->bssfile,newname);
            m = g_strdup_printf("%s already exists and will be renamed to %s. Continue?",
                        pbsi->bssfile,newname);
            messresult = messQuery(m);
            g_free(m);
            if (messresult == 0) return;
            rename(pbsi->bssfile,newname);
        }
        else
        {
            remove(pbsi->bssfile);
            if (stat(pbsi->bssfile, &s) == 0)
            {
                printf("Unable to remove %s; remove it or choose a different name to continue.\n",pbsi->bssfile);fflush(0);
                return;
            }
        }
    }
    
    if (!pbsi->split)
    {
        really_write_bss_file(pbsi,0);
        return;
    }    
    
    /* Do the contig splitting, making use of a sort on ctg number */

    mkdir(pbsi->bssfile,ALL_ACCESS);
    bss_sort_hitlist(BSS_CTG,1,pbsi);
 
    ihit = 0;  // this tracks the last hit written by the current iteration
    while (ihit < arrayMax(pbsi->bss_hits))
    {
        really_write_bss_file(pbsi,&ihit);
        ihit++;
    }
}

/*
*       This function does several things. First, it creates the query hit and 
*       contig hit tables, i.e., tables of hit data aggregated by query or contig hit.
*
*       Second, it fills out the BSS_SEQCTG data field for sequence->bes searches,
*       with the value being an index into the query hit table. This is necessary
*       for the MTP, and also for the clone ordering code. 
*/      
void compute_ctg_query_tables(struct bss_instance* pbsi,int istart, int iend)
{ 
    int i,j;
    FPC_TREE qtree;
    int queries_with_hits = 0;
    int seqctg;
    int best_ctg_score;
    int best_ctg = 0;
    struct ctgsHitlistType* pCtgHit;
    CTG_HIT_DATA *pch;
    BSS_HIT* hit;
    int this_ctg;
    QUERY_HIT_DATA* pqd;

    /*  Collect all the hits grouped by query sequence. 
        We use an array indexed by the SeqCtg number, previously determined.
    */

    init_fpc_tree(&qtree);
    pbsi->bss_ctghits = arrayCreate(max_contig+1, CTG_HIT_DATA) ;
    for (i = 0; i <= max_contig; i++)
    {
        pch = arrayp(pbsi->bss_ctghits,i,CTG_HIT_DATA);
        memset(pch,0,sizeof(CTG_HIT_DATA));
        pch->contig = i;
        pch->order = i;
    } 

    pbsi->bss_queryhits = arrayCreate(0, QUERY_HIT_DATA) ;   

    for (i = istart; i <= iend; i++)
    {
        hit = arrp(pbsi->bss_hits,i,BSS_HIT);

        if (hit->filtered) continue;

        this_ctg = hit->data[BSS_CTG].i; 

        pch = arrp(pbsi->bss_ctghits,this_ctg,CTG_HIT_DATA);
        pch->cloneHits++;
        pch->cst += hit->data[BSS_SCORE].i;


        seqctg = hit->data[BSS_SEQCTG].i;
        if (seqctg >= arrayMax(pbsi->bss_queryhits))
        {
            for (j = arrayMax(pbsi->bss_queryhits); j <= seqctg; j++)
            {
                pqd = arrayp(pbsi->bss_queryhits,j,QUERY_HIT_DATA);
                memset(pqd,0,sizeof(QUERY_HIT_DATA));
                pqd->seqCtg = j;
            } 
        } 
        pqd = arrp(pbsi->bss_queryhits,seqctg,QUERY_HIT_DATA);  
        strcpy(pqd->query,hit->data[BSS_MARKER].str);

        assert(pqd);        
        pqd->hits++;
        pqd->size = hit->data[BSS_QLEN].i;
    
        pCtgHit = find_ctg_hit(this_ctg, pqd->ctgsHitlist);
        if (!pCtgHit) 
        {
            add_to_ctgsHitlist(this_ctg, &pqd->ctgsHitlist);
            pCtgHit = find_ctg_hit(this_ctg, pqd->ctgsHitlist);                    
            assert(pCtgHit);
            pCtgHit->contig = this_ctg;
        }
        pCtgHit->cst += hit->data[BSS_SCORE].i;
        pCtgHit->cloneHits++;
    }



    /* get the best ctg etc. */

    for (i = 0; i < arrayMax(pbsi->bss_queryhits); i++)
    {
        pqd = arrp(pbsi->bss_queryhits,i,QUERY_HIT_DATA);
        if (pqd->hits > 0)
        {
            queries_with_hits++;
            pCtgHit = pqd->ctgsHitlist;
            best_ctg_score = 0;
            best_ctg = 0;
            while (pCtgHit)
            {
                pqd->numCtgsHit++;
                if (pCtgHit->cloneHits > best_ctg_score)
                {
                    best_ctg_score = pCtgHit->cloneHits;
                    best_ctg = pCtgHit->contig;
                }                     
                pCtgHit = pCtgHit->next;            
            }
            pqd->bestCtg = best_ctg;
            pqd->hitsBestCtg = best_ctg_score;
        }            
    }
}
/* TODO: update the overall stats maintained in the bss_instance if we want to 
        save an overall summary */

void really_write_bss_file(struct bss_instance* pbsi, int* pihit)
{
    FILE* f;
    int i,j;
    char line[1000];
    char field[100];
    char hitsctgs[20];
    char bestctg[20];
    BSS_HIT* hit;
    QUERY_HIT_DATA* pqd;
    CTG_HIT_DATA* pch;
    char bssfile[MAXPATHLEN];

    const gchar* program_name = NULL;
    guint n_db_files = 0;
    gchar* domain_pars = NULL;
    gchar* score = NULL;
    gchar* dbs = NULL;
    int split_ctg = -1;
    int split;
    int istart;
    int iend = arrayMax(pbsi->bss_hits) - 1;
    int this_ctg;
    BSS_FILTER bf;
    
    split = (pihit == NULL ? 0 : 1);
    istart = (pihit == NULL ? 0 : *pihit);


    if (split)
    {
        split_ctg = arrp(pbsi->bss_hits,*pihit,BSS_HIT)->data[BSS_CTG].i;
        sprintf(bssfile,"%s/ctg%d.bss",pbsi->bssfile,split_ctg);
    }
    else
    {
        strcpy(bssfile,pbsi->bssfile);
    }

    f = fopen(bssfile,"w+");    
    if (f == NULL)
    {
        messout("Unable to open %s\n",bssfile);  
        return;      
    }

    /* Figure out the range of hits spanned by this contig */

    for (i = istart; i < arrayMax(pbsi->bss_hits); i++)
    {
        hit = arrp(pbsi->bss_hits,i,BSS_HIT);
        this_ctg = hit->data[BSS_CTG].i; 
        if (split) 
        {
            if (this_ctg != split_ctg)
            {
                break;  
            }
            iend = i;
            *pihit = i;
        } 
    }

    compute_ctg_query_tables(pbsi,istart, iend);


    /********** Header ****************/



    n_db_files =  pbsi->dbs->len;

    switch (pbsi->program) {
    case BLAST:
        program_name = "BLAST";
        score = g_strdup_printf("Expectation Value: %0.0e\n", atof(pbsi->cutoff_str));
        break;
    case MEGABLAST:
        program_name = "MEGABLAST";
        score = g_strdup_printf("Expectation Value: %0.0e\n", atof(pbsi->cutoff_str));
        break;
    case BLAT:
        program_name = "BLAT";
        score = g_strdup_printf("Blat Score: %d\n", pbsi->blat_score);
        break;
    default:
        g_assert_not_reached();
    }

    if (pbsi->dbs->data != NULL) {
       dbs = g_strjoinv(",", (gchar**)pbsi->dbs->data);
    }
    else {
       dbs = "";
    }

    fputs("***BSS V3.0 results***\n\n", f);
    fprintf(f, "Query directory: %s\n", pbsi->query_dir);
    fprintf(f, "Query file: %s\n", pbsi->query_file);
    fprintf(f, "Database directory: %s\n", pbsi->db_dir);
    fprintf(f, "Database files: %s\n", dbs);
    if (split)
    {
        fprintf(f,"split_bss:ctg%d\n",split_ctg);
    }
    else
    {
        fprintf(f,"split_bss:no\n");
    }
    if (domain_pars) fputs(domain_pars, f);
    fprintf(f, "Program: %s\n", program_name);
    fputs(score, f);
    fprintf(f, "Additional Parameters: %s\n",pbsi->xtraParm);
    fprintf(f, "Total number of query sequences: %u\n", pbsi->num_initial_queries);

    /* write both old and new filters */
    for (i = 0; i < pbsi->old_filter_history->len; i++)
    {
        fprintf(f, "Filter:%s\n",g_array_index(pbsi->old_filter_history,char*,i));
    }
    for (i = 0; i < pbsi->filter_history->len; i++)
    {
        bf = g_array_index(pbsi->filter_history,BSS_FILTER,i);
        fprintf(f, "Filter:%s,%s,%s results\n",bf.type,bf.search,bf.results);
    }

    fputs("\n",f);

    /********* Query hit table ********/
    fputs("#Query hit summary\n",f);
    fprintf(f,"%-18s%-11s%-14s%-11s\n","Sequence","Len","Hits/Ctgs","BestCtg/Hits");



    for (i = 0; i < arrayMax(pbsi->bss_queryhits); ++i) 
    {
        pqd = arrayp(pbsi->bss_queryhits,i,QUERY_HIT_DATA);
        if (pqd->hits == 0) continue;
        sprintf(hitsctgs,"%d/%d",pqd->hits,pqd->numCtgsHit);
        sprintf(bestctg,"%d/%d",pqd->bestCtg,pqd->hitsBestCtg);
        fprintf(f,"%-17s %-10ld %-13s %-10s",pqd->query,pqd->size,hitsctgs,bestctg);


        fprintf(f,"\n");

    }

    fputs("\n\n", f);



    /*********** Contig hit table **********/

    fputs("#Contig hit summary\n",f);
    if (!split)
    {
        for (i = 1; i < arrayMax(pbsi->bss_ctghits); ++i) 
        {
            pch = arrp(pbsi->bss_ctghits,i,CTG_HIT_DATA);
            if (pch->cst == 0) continue;
            fprintf(f,"Ctg%d   CST %d   CloneHits %d\n",i,pch->cst,pch->cloneHits);
        }
    }
    else
    {
        pch = arrp(pbsi->bss_ctghits,split_ctg,CTG_HIT_DATA);
        fprintf(f,"Ctg%d   CST %d   CloneHits %d\n",split_ctg,pch->cst,pch->cloneHits);
    }
    fputs("\n\n", f);


 
    /************* Hit table ******************/

    fputs("#Hit table\n",f);
    output_column_headers(f);fflush(0);
    for (i = istart; i <= iend && i < arrayMax(pbsi->bss_hits); i++)
    {
        line[0] = 0;
        hit = arrp(pbsi->bss_hits,i,BSS_HIT);
        if (hit->filtered > 0) continue;
        for (j = 0; j < bss_ncols; j++)
        {         
            bss_format_field(field,hit,bss_column_order[j]);  
            strcat(line,field);
        }
        strcat(line,"\n");
        fputs(line,f);fflush(0);
    }

    fclose(f);
}
int bss_split_line(char* _line)
{
    int i = 0;
    char* ptr;
    char* line;

    line = strdup(_line);
    for (i = 0; i < 30; i++)
    {
        bss_fields[i][0] = 0;
    }
    ptr = strtok(line," ");
    for (i = 0; i < 30; i++)
    {
        if (ptr)
        {
            safe_strncpy(bss_fields[i],ptr,BSS_FIELD_MAXSIZE); 
        }
        else
        {
            break;
        }
        ptr = strtok(0," \n");
    }
    free(line);
    return i;
}
void bss_init_column_order(char* line)
{
    int i,j;
    int found;
    bss_ncols = 0;

    bss_split_line(line);
    for (i = 0; i < BSS_NUMTYPES; i++)
    {
        bss_column_order[i] = BSS_NUMTYPES; 
        if (bss_fields[i][0] == 0)
        {
            break;
        } 
        found = 0;
        for (j = 0; j < BSS_NUMTYPES; j++)
        {
            if (0 == strcmp(bss_fields[i],bss_headers[j]))
            {
                bss_column_order[i] = j;
                found = 1;
                break;
            }   
        }
        if (!found)
        {
            printf("unknown column %s in bss file\n",bss_fields[i]);fflush(0);
        }
        bss_ncols++;
    }
    //printf("matched %d columns\n",bss_ncols);fflush(0);
}
void split_ctglr(char* ctglr, int* ctg, char** LR)
{
    char* p = strdup(ctglr);
    int len = strlen(p);

    *ctg = 0;
    *LR = strdup("-");
    if (len > 0)
    {
        if (p[len-1] == 'L')
        {
            *LR = strdup("L");
            p[len-1] = 0;
        }
        else if (p[len-1] == 'R')
        {
            *LR = strdup("R");
            p[len-1] = 0;
        }
    }
    else
    {
        printf("Empty contig field found\n");fflush(0);        
    }

    *ctg = strtol(p,0,10);
}
void fill_bss_hit(BSS_HIT* phit)
{
    int i;
    BSS_TYPE field;
    memset(phit,0,sizeof(BSS_HIT));
    for (i = 0; i < bss_ncols; i++)
    {
        field = bss_column_order[i];
        switch (field)
        {
            case BSS_QLEN:
            case BSS_QSTART:
            case BSS_QEND:
            case BSS_TSTART:
            case BSS_TEND:
            case BSS_TLEN:
            case BSS_SEQCTG:
            case BSS_CTG:
            case BSS_SCORE:
            case BSS_HITLEN:
            case BSS_INTRON:
                phit->data[field].i = atoi(bss_fields[i]);
            break;

            case BSS_SEQ:
            case BSS_BES:
            case BSS_MARKER:
            case BSS_RC:
            case BSS_CLONE:
            case BSS_EVALUE:
            case BSS_LR:
            case BSS_QUERY:
            case BSS_TARGET:
                phit->data[field].str = strdup(bss_fields[i]);
            break;
            case BSS_IDENTITY:
            case BSS_MATCH:
                sscanf(bss_fields[i],"%d",&phit->data[field].i);
                break;
            case BSS_CTGLR:
                phit->data[field].str = strdup(bss_fields[i]);
                split_ctglr(bss_fields[i],&phit->data[BSS_CTG].i,&phit->data[BSS_LR].str);
                break;
            default:
                assert(0);
            break;
        } 
    }
}

// Figure out the contig for each hit based on its clone.
// WMN 10/08 - hits for clones which are not in the project anymore should not be present at this point

void bss_check_contigs(BSS_INST* pbsi)
{
    int i,c;
    BSS_HIT* h;
    char* clonename;

    for (i = 0; i < arrayMax(pbsi->bss_hits); i++)
    {
        h = arrp(pbsi->bss_hits,i,BSS_HIT);
        if (!fppFind(acedata,h->data[BSS_CLONE].str,&c,cloneOrder))
        {
            //printf("clone %s is no longer in the FPC project\n",h->data[BSS_CLONE].str);
            continue;
        }
        check_in_ctg2(c,&h->data[BSS_CTG].i,&clonename,&h->data[BSS_LR].str[0]);
        if (h->data[BSS_LR].str[0] != '-')
        {
            h->data[BSS_CTGLR].str = g_strdup_printf("%d%c",h->data[BSS_CTG].i,h->data[BSS_LR].str[0]);
        }
        else
        {
            h->data[BSS_CTGLR].str = g_strdup_printf("%d",h->data[BSS_CTG].i);
        }        
    }   
}

int read_bss_file(char* path, struct bss_instance* pbsi)
{
    char oneline[1024];
    char dbs[1000];
    char version[6];

    FILE* readfile;
    DIR* dir;
    struct dirent* dent;
    char fields[4][256];
    int i;
    int ctg, cst, clonehits;
    BSS_HIT* pch;
    char* ptr, *p2;
    gchar* tempstr;
    GArray *bss_files = NULL;
    int ibss;
    struct stat s;
    bss_files = g_array_new(FALSE, FALSE, sizeof(GArray*));
	CLONE c;
	int ic;

    assert(path);
    assert(pbsi);

    strcpy(pbsi->bssfile,path);

    /* see if it's a directory; if so, we assume it is a split-by-contig
            output and read all the files */


    if (stat(path, &s) != 0)
    {
       printf("unable to open %s\n",path);fflush(0);
       return 0;
    }

    if (!S_ISDIR(s.st_mode))
    {
        tempstr = g_strdup(path);
        g_array_append_val(bss_files,tempstr);
    }
    else 
    {
        dir = opendir(path);
        if (dir != NULL)
        {
            while((dent = readdir(dir)) != NULL)
            {                     
                if (0 == strncmp(dent->d_name,"ctg",3))
                {
                    tempstr = g_strdup_printf("%s/%s",path,dent->d_name);
                    g_array_append_val(bss_files,tempstr);
                }
            }            
            closedir(dir);
        }
    }

    i = 0;

    for (ibss = 0; ibss < bss_files->len; ibss++)
    {
                
        readfile = fopen(g_array_index(bss_files,gchar*,ibss),"r");

        /****** HEADER **********************************************/

        /* version:   ***BSS V3.0 results***    */
        if(FSCANLINE(oneline)<1) goto error;
        if(sscanf(oneline,"***BSS V%s",version)<1) ERRLINE(oneline,0);

        if (!strstr(version,"3.0")) 
        {
            fprintf(stderr,"Unable to parse old BSS file version %s\n",version);
            fclose(readfile);
            return 0;
        }

        if(FSCANLINE(oneline)<1) goto error;


        if(FSCANLINE(oneline)<1) goto error;
        if(sscanf(oneline,"Query directory: %s",pbsi->query_dir)<1) ERRLINE(oneline,0)

        if(FSCANLINE(oneline)<1) goto error;
        if(sscanf(oneline,"Query file: %s",pbsi->query_file)<1) ERRLINE(oneline,0)

        if(FSCANLINE(oneline)<1) goto error;
        if(sscanf(oneline,"Database directory: %s", pbsi->db_dir)<1) ERRLINE(oneline,0)

        if(FSCANLINE(oneline)<1) goto error;
        if(sscanf(oneline,"Database files: %s", dbs)<1) ERRLINE(oneline,0)
        pbsi->dbs = g_array_new(TRUE, FALSE, sizeof(gchar*));
        ptr = strtok(dbs,",");
        while (ptr)
        {
            tempstr = g_strdup(ptr);
            g_array_append_val(pbsi->dbs,tempstr);
            ptr = strtok(0,",");
        }

        /* see if it was split by contigs */

        if(FSCANLINE(oneline)<1) goto error;
        if (strncmp(oneline,"split_bss",5)) ERRLINE(oneline,0)
        if (strstr(oneline,":no"))
        {
            pbsi->split = 0;
        }
        else
        {
            pbsi->split = 1;
            if (sscanf(oneline,"split_bss:ctg%d",&pbsi->split_ctg) < 1) ERRLINE(oneline,0)
        }


        /* program type */
        if(FSCANLINE(oneline)<1) goto error;
        if (strstr(oneline,"Program:"))
        {
            if (strstr(oneline, "BLAT")) 
            {
                pbsi->program = BLAT;
            }
            else if (strstr(oneline, "MEGABLAST")) 
            {
                pbsi->program = MEGABLAST;
            }
            else if (strstr(oneline, "BLAST")) 
            {
                pbsi->program = BLAST;
            } 
            else  ERRLINE(oneline,0)    
        }


        if(FSCANLINE(oneline)<1) goto error;
        if (pbsi->program != BLAT) 
        {
             if(sscanf(oneline,"Expectation Value: %s",pbsi->cutoff_str)<1) ERRLINE(oneline,0)
        }
        else 
        {
            if(sscanf(oneline,"Blat Score: %d",&pbsi->blat_score)<1) ERRLINE(oneline,0)
        }

        if(FSCANLINE(oneline)<1) goto error;
        if (!strstr(oneline,"Additional Parameters")) ERRLINE(oneline,0)
        sscanf(oneline,"Additional Parameters: %[^\n]",pbsi->xtraParm);

        if(FSCANLINE(oneline)<1) goto error; 
        sscanf(oneline,"Total number of query sequences: %d",&pbsi->num_initial_queries);

        /* read in the old filter lines */
        pbsi->filter_history = g_array_new(FALSE,FALSE,sizeof(BSS_FILTER));
        pbsi->old_filter_history = g_array_new(FALSE,FALSE,sizeof(char*));
        do
        {
            if(FSCANLINE(oneline)<1) goto error;
            if (!strncmp(oneline,"Filter:",7))
            {
                ptr = oneline + strlen("Filter:");
                p2 = strdup(ptr) ;
                g_array_append_val(pbsi->old_filter_history,p2); 
            }
        }
        while(strncmp(oneline,"#Query",6) != 0);
        if(FSCANLINE(oneline)<1) goto error;

        /****** QUERY TABLE **********************************************/
        /* skip it and recompute from hit data */

        //pbsi->bss_queryhits = arrayCreate(0, QUERY_HIT_DATA) ;
        while(1)
        {
            if(FSCANLINE(oneline)<1) goto error;
            if (sscanf(oneline,"%s %s %s %s",fields[0],fields[1],fields[2],fields[3]) < 4)
            {
                break;
            }
            continue;       

        }

        do
        {
          if(FSCANLINE(oneline)<1) goto error;
        }
        while(strncmp(oneline,"#Contig",7) != 0);


        /****** CONTIG TABLE **********************************************/
        /* skip it an recompute from hit data */

        while(1)
        {
            if(FSCANLINE(oneline)<1) ERRLINE(oneline,0)
            if (sscanf(oneline,"Ctg%d  CST %d CloneHits %d",&ctg,&cst,&clonehits) < 3)  break;
            continue;  

        }


        /****** HIT TABLE **********************************************/

        do
        {
          if(FSCANLINE(oneline)<1) goto error;
        }
        while(strncmp(oneline,"#Hit",4) != 0);
        if(FSCANLINE(oneline)<1) ERRLINE(oneline,0)
        bss_init_column_order(oneline);


        if (ibss == 0)
        {
            pbsi->bss_hits = arrayCreate(0, BSS_HIT);
        }
        for (ic = 0; ic < bss_ncols; ic++)
        {
            if (BSS_CLONE == bss_column_order[ic])
			{
				break;
			}
		}


        while(1)
        {
            if(FSCANLINE(oneline) == 0) break;        
            if (bss_split_line(oneline) != bss_ncols)  break;

            if (!fppFind(acedata,bss_fields[ic],&c,cloneOrder))
            {
                printf("clone %s is no longer in the FPC project\n",bss_fields[ic]);
                continue;
            }


            pch = arrayp(pbsi->bss_hits,i,BSS_HIT);
            memset(pch,0,sizeof(BSS_HIT));
            fill_bss_hit(pch);
			pch->order = i;                
            i++; 
			
        }
        //printf("Hits: %d\n",i);fflush(0);



        fclose(readfile);


    }

    bss_check_contigs(pbsi);

    compute_ctg_query_tables(pbsi,0, arrayMax(pbsi->bss_hits) - 1);
    return 1;

error:    
    return 0;
}






